package appcus

import (
	"counter-help/admin/server/global"
	"counter-help/admin/server/model/app"
	"counter-help/admin/server/model/common/response"
	"crypto/md5"
	"encoding/hex"
	"encoding/xml"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-resty/resty/v2"
	"net/http"
	"sort"
	"strings"
	"time"
)

// CusOrderPayApi 小程序订单支付功能
type AppCusOrderPayApi struct{}

const (
	//ApiKeyv3  = "CDtongjisuisuinian202312shanglue"
	ApiKeyv2  = "CDshanglue202312tongjisuisuinian"
	AppID     = "wx397aa4c18c836e69"
	MchID     = "1694609563"
	NotifyURL = "http://5526f494.r6.cpolar.top/api/appCusOrderPay/notify" // 支付回调地址
)

// AppOrderPay 微信订单支付
func (p *AppCusOrderPayApi) AppOrderPay(c *gin.Context) {
	// 获取订单 和 订单价格
	var orderReq app.OrderRequest
	if err := c.ShouldBindJSON(&orderReq); err != nil {
		global.GVA_LOG.Error("Invalid request::" + err.Error())
		response.FailWithMessage("Invalid request::"+err.Error(), c)
		return
	}

	// 生成统一下单请求的参数
	params := map[string]string{
		"appid":            AppID,
		"mch_id":           MchID,
		"nonce_str":        generateNonceStr(),
		"body":             orderReq.Body,
		"out_trade_no":     orderReq.OutTradeNo,
		"total_fee":        fmt.Sprintf("%d", orderReq.TotalFee),
		"spbill_create_ip": "139.162.62.102", // 服务器IP
		"notify_url":       NotifyURL,
		"trade_type":       "JSAPI", // 小程序支付
		"sign_type":        "MD5",
		"openid":           orderReq.OpenID,
	}

	// 生成签名
	sign := generateSign(params, ApiKeyv2)
	params["sign"] = sign

	// 生成XML请求体
	xmlRequest, err := generateXMLRequest(params)
	if err != nil {
		global.GVA_LOG.Error("生成XML请求失败 Error::" + err.Error())
		response.FailWithMessage("生成XML请求失败 Error::"+err.Error(), c)
		return
	}

	// 向微信支付发起请求
	client := resty.New()
	resp, err := client.R().
		SetHeader("Content-Type", "application/xml").
		SetBody(xmlRequest).
		Post("https://api.mch.weixin.qq.com/pay/unifiedorder")
	if err != nil {
		global.GVA_LOG.Error("与微信通信失败 Error::" + err.Error())
		response.FailWithMessage("与微信通信失败 Error::"+err.Error(), c)
		return
	}

	// 解析微信支付返回的数据
	var unifiedOrderResp app.UnifiedOrderResponse
	err = xml.Unmarshal(resp.Body(), &unifiedOrderResp)
	if err != nil {
		global.GVA_LOG.Error("解析微信返回失败 Error::" + err.Error())
		response.FailWithMessage("解析微信返回失败 Error::"+err.Error(), c)
		return
	}

	// 如果返回成功，返回预支付ID
	if unifiedOrderResp.ReturnCode == "SUCCESS" {
		// 前端需要的支付参数
		timestamp := fmt.Sprintf("%d", time.Now().Unix())
		pkg := "prepay_id=" + unifiedOrderResp.PrepayID

		// 生成签名
		paramsGenOrder := map[string]string{
			"appId":     AppID,
			"package":   pkg,
			"nonceStr":  unifiedOrderResp.NonceStr,
			"timeStamp": timestamp,
			"signType":  "MD5",
		}

		paySign := generateSign(paramsGenOrder, ApiKeyv2)
		paramsGenOrder["paySign"] = paySign

		// 返回预支付交易会话标识
		response.OkWithDetailed(paramsGenOrder, "微信预订单创建成功", c)
	} else {
		global.GVA_LOG.Error("解析微信返回失败 Error::" + unifiedOrderResp.ReturnMsg)
		response.FailWithMessage("解析微信返回失败 Error::"+unifiedOrderResp.ReturnMsg, c)
		return
	}

}

// HandlePaymentNotification 接收微信回调通知
func (p *AppCusOrderPayApi) HandlePaymentNotification(c *gin.Context) {
	var notifyData app.PaymentNotification
	if err := c.ShouldBindXML(&notifyData); err != nil {
		c.XML(http.StatusBadRequest, gin.H{"return_code": "FAIL", "return_msg": "Invalid XML"})
		return
	}

	// 准备签名参数
	params := map[string]string{
		"appid":          notifyData.AppID,
		"bank_type":      notifyData.BankType,
		"cash_fee":       notifyData.CashFee,
		"fee_type":       notifyData.FeeType,
		"is_subscribe":   notifyData.IsSubscribe,
		"mch_id":         notifyData.MchID,
		"nonce_str":      notifyData.NonceStr,
		"openid":         notifyData.Openid,
		"out_trade_no":   notifyData.OutTradeNo,
		"result_code":    notifyData.ResultCode,
		"return_code":    notifyData.ReturnCode,
		"time_end":       notifyData.TimeEnd,
		"total_fee":      notifyData.TotalFee,
		"trade_type":     notifyData.TradeType,
		"transaction_id": notifyData.TransactionID,
	}

	// 计算签名
	expectedSign := generateSign(params, ApiKeyv2)

	// 验证签名
	if notifyData.Sign != expectedSign {
		c.XML(http.StatusForbidden, gin.H{"return_code": "FAIL", "return_msg": "签名验证失败"})
		return
	}

	// 返回处理结果
	if notifyData.ReturnCode == "SUCCESS" && notifyData.ResultCode == "SUCCESS" {
		// 处理订单支付成功逻辑，比如更新订单状态等
		// 更新本系统订单状态
		orderId := getPrefixBeforeFirstUnderscore(notifyData.OutTradeNo)
		fee := notifyData.TotalFee
		dbErr := appOrderPayService.AppOrderPay(orderId, fee)
		if dbErr != nil {
			// 支付失败逻辑
			c.XML(http.StatusOK, gin.H{"return_code": "FAIL", "return_msg": "支付失败"})
		}
		c.XML(http.StatusOK, gin.H{"return_code": "SUCCESS", "return_msg": "OK"})
	} else {
		// 支付失败逻辑
		c.XML(http.StatusOK, gin.H{"return_code": "FAIL", "return_msg": "支付失败"})
	}
}

// 生成随机字符串
func generateNonceStr() string {
	return fmt.Sprintf("%d", time.Now().UnixNano())
}

// 生成签名
func generateSign(params map[string]string, apiKey string) string {
	var keys []string
	for key := range params {
		// 排除 sign 参数本身
		if key != "sign" {
			keys = append(keys, key)
		}
	}

	// 排序参数
	sort.Strings(keys)

	var paramStr string
	for _, key := range keys {
		paramStr += key + "=" + params[key] + "&"
	}
	paramStr += "key=" + apiKey // 最后加上 API 密钥

	// 使用 MD5 加密并转为大写
	return md5Hash(paramStr)
}

// MD5 加密
func md5Hash(s string) string {
	hash := md5.New()
	hash.Write([]byte(s))
	return strings.ToUpper(hex.EncodeToString(hash.Sum(nil)))
}

// 生成XML请求体
func generateXMLRequest(params map[string]string) (string, error) {
	xmlStr := "<xml>"
	for key, value := range params {
		xmlStr += fmt.Sprintf("<%s>%s</%s>", key, value, key)
	}
	xmlStr += "</xml>"
	return xmlStr, nil
}

func getPrefixBeforeFirstUnderscore(input string) string {
	// 找到第一个下划线的位置
	index := strings.Index(input, "_")
	// 如果找到下划线，返回下划线前的子字符串；否则返回整个字符串
	if index != -1 {
		return input[:index]
	}
	return input
}
